#!/usr/bin/env python
# -*- encoding: utf-8 -*-
'''
@File    :   check_user_login_status.py
@Time    :   2024-08-09 12:27:24
@Author  :   chakcy 
@Email   :   947105045@qq.com
@description   :   检查用户登录状态装饰器
'''

from typing import Any, Protocol

from fastapi import Request

from ..dependencies.redis import RedisDependency, RedisOperation
from ..models import CommonResponseModel


class CheckLoginStatusFunc(Protocol):
    async def __call__(self, 
                       request: Request, 
                       redis: RedisDependency, 
                       *args, **kwargs) -> Any:
        ...

async def checkUserLoginStatus(request: Request, redis: RedisDependency) -> int:
    """
    检查用户登录状态

    :param user_account_id: 用户账户ID
    :param redis: Redis依赖
    :return: 如果用户已登录返回True，否则返回False
    """
    user_account_id = request.state.data.get("userAccountId", "")
    token = request.state.token
    async with redis.pipeline() as pipe:
        pipe_operation = RedisOperation(pipe)
        await pipe_operation.item().get_value(user_account_id)
        result = await pipe.execute()
        if result[0] is None:
            return 1
        if result[0] != token:
            return 2
        return 0
    

def check_login_status(func: CheckLoginStatusFunc) -> CheckLoginStatusFunc :
    """
    检查用户登录状态装饰器
    必须提供data和redis参数

    参数:
    - func: 被装饰的异步函数
    - data: 包含用户信息的字典，必须包含 'userAccountId' 键
    - redis: RedisDependency 实例

    返回:
    - 如果用户已登录，执行被装饰的函数并返回其结果
    - 如果用户未登录，返回包含错误信息的 CommonResponseModel 对象

    注意：函数传参时不能使用位置参数，必须使用关键字参数
    """
    async def wrapper(*args, **kwargs):
        request = kwargs.get('request')
        redis = kwargs.get('redis')
        
        if not request or not redis:
            raise ValueError("Request and RedisDependency must be provided")
        
        status = await checkUserLoginStatus(request, redis)

        if status == 1:
            return CommonResponseModel(data={}, code=401, message="用户未登录").model_dump()
        
        elif status == 2:
            return CommonResponseModel(data={}, code=401, message="用户登录已失效，请重新登录").model_dump()
        
        elif status == 0:
            return await func(*args, **kwargs)
    return wrapper

